Выбор задачи

Я решил поставить задачу распознавания кошачьих мордочек, а именно разделения фотографий котов на те, где изображен мой кот Кубик, и те, где изображен другой кот. На фотографии морды кота крупным планом хорошо заметны некоторые признаки, по которым можно узнать конкретного кота, например:

Сбор и подготовка данных

Какие данные использовались

Для моих целей очень хорошо подходит следующий датасет:

https://github.com/fferlito/Cat-faces-dataset

Датасет содержит 30 тысяч кошачьих мордочек в разрешении 64х64. Изображения уже подготовлены к обучению и никакой дополнительной обработки не потребовалось.\ На своем телефоне я обнаружил 90 фотографий, на которых хорошо видно мордочку Кубика. Я обрезал эти фотографии таким образом, чтобы получились квадратные изображения, на которых большую часть места занимает морда кота. Также я старался оставлять в кадре уши, так как они у него очень большие и потенциально это может быть одним из признаков, которые выучит нейросеть.\ В итоге я имею 90 фотографий Кубика и 1500 фотографий других котов. Так как размер положительного класса в датасете ограничен, каждую эпоху будут тренироваться все фотографии Кубика, к которым применены случайные аугментации, и такое же количество случайно выбранных других котов. Данная техника позволяет тренировать каждую эпоху на отличающихся данных, что будет компенсировать ограниченность датасета.

Датасет тут: https://drive.google.com/drive/folders/17EBCpztFjJaaDpH3OlbLUQYGVlCB4g38?usp=sharing

Предобработка и аугментация изображений

Я использую библиотеку albumentations, которая реализует такие же трансформации, как в PyTorch, но работают они быстрее.\ Для загрузки датасета используется готовый класс из PyTorch, но в связи с особенностями реализации библиотеки albumentations мне пришлось создать класс-наследник и переопределить в нем метод получения изображения по индексу.

Для загрузки случайных трансформаций исходных изображений и обеспечения сбалансированности выборки реализован загрузчик данных и его итератор.

!pip install -U git+https://github.com/albumentations-team/albumentations

Изображения для тренировки приводятся к одинаковому размеру, после чего немного подрезаются (случайным образом), изображение сдвигается, и накладывается шум случайного вида.\ Изображения для тестов просто приводятся к размеру и подрезаются.

Обучение нейросетей

Вспомогательный класс, который строит график.

Функция тренировки

Готовая архитектура

В качестве готовой архитектуры была выбрана SqueezeNet, так как она специально разрабатывалась с малым числом параметров, и с расчетом на быстрое обучение и малый размер модели. Для простой задачи распознавания одного кота она должна подойти.

Видим, что несмотря на малый размер данных, сеть всего за несколько эпох вышла на результат около 80%, и за примерно за 30 эпох натренировалась до точности 85%.\ Результат неплохой, но можно лучше. Мое предположение - сеть заточена под imageNet, и из коробки, без дополнительной настройки, не покажет отличных результатов для другой задачи.\ Обучается сеть сравнительно быстро, на одну эпоху тренировки уходит около двух секунд.

Своя архитектура

Сначала я решил сделать максимально простую архитектуру из нескольких слоев:

Я решил добавить функцию активации и слой батч нормализации. Это небольшое улучшение дало прирост примерно в 20% уже на первых нескольких эпохах!

Данная простая архитектура в моей задаче показывает себя гораздо лучше, чем SqueezeNet:

Как было сказано выше, мое мнение - сквизнет просто не отпимизирован из коробки для подобной задачи, поэтому простая архитектура тут выигрывает показывает такие же результаты гораздо раньше, и еще и тренируется быстрее за счет своей простоты.

На графике видно, что после нескольких первых эпох дальнейшего улучшения почти не происходит. Дальше тренировать смысла нет.

Приложение

Тут можно посмотреть на котиков.